﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Threading;
using System.Diagnostics;

namespace MutliServiceController
{
    public class ServiceItem : IDisposable
    {
        private ServiceController controller;
        private ServiceControllerStatus lastStatus;
        private int sleepTime = 1000;
        private Thread statusThread;
        OnStatusChanged_Handler resetHandler;
        private ServiceMenuItem menuItem;
        private bool available = true;

        public ServiceItem(string serviceName)
        {
            try
            {
                controller = new ServiceController(serviceName, ".");
                statusThread = new Thread(new ThreadStart(StatusChecker));
                statusThread.Start();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error when init Service '" + serviceName + "' : " + ex.Message);
                this.available = false;
            }
        }

        public bool Available
        {
            get
            {
                return this.available;
            }
        }

        public string Name
        {
            get { return controller.DisplayName; }
        }

        public string ServiceName
        {
            get { return controller.ServiceName; }
        }

        public ServiceMenuItem MenuItem
        {
            get { return this.menuItem; }
            set { this.menuItem = value; }
        }

        public ServiceControllerStatus Status
        {
            get { return this.controller.Status; }
        }

        public override string ToString()
        {
            return controller.DisplayName + " (" + controller.Status.ToString() + ")";
        }

        public delegate void OnStatusChanged_Handler(ServiceItem item, ServiceControllerStatus status);
        public event OnStatusChanged_Handler OnStatusChanged;

        private void StatusChecker()
        {
            try
            {
                while (true)
                {
                    controller.Refresh();
                    if (controller.Status != lastStatus)
                    {
                        lastStatus = controller.Status;
                        if (OnStatusChanged != null)
                        {
                            OnStatusChanged(this, controller.Status);
                        }
                    }
                    Thread.Sleep(sleepTime);
                }
            }
            catch (ThreadAbortException ex)
            {
                Debug.WriteLine("Error for Service '" + this.ServiceName + "' : " + ex.Message);
                this.available = false;
            }
        }

        public void Start()
        {
            try
            {
                this.controller.Start();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error for Service '" + this.ServiceName + "' : " + ex.Message);
                this.available = false;
            }
        }

        public void Stop()
        {
            try
            {
                this.controller.Stop();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error for Service '" + this.ServiceName + "' : " + ex.Message);
                this.available = false;
            }
        }

        public void Reset()
        {
            try
            {
                if (resetHandler == null)
                {
                    resetHandler = new OnStatusChanged_Handler(ServiceItem_OnStatusChangedForReset);
                    this.OnStatusChanged += resetHandler;
                    this.Stop();
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error for Service '" + this.ServiceName + "' : " + ex.Message);
                this.available = false;
            }
        }

        void ServiceItem_OnStatusChangedForReset(ServiceItem item, ServiceControllerStatus status)
        {
            try
            {
                if (status == ServiceControllerStatus.Stopped)
                {
                    this.Start();
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Error for Service '" + this.ServiceName + "' : " + ex.Message);
                this.available = false;
            }
            finally
            {
                this.OnStatusChanged -= resetHandler;
                resetHandler = null;
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            this.statusThread.Abort();
            this.controller.Dispose();
        }

        #endregion
    }
}
